package com.sinosoft.hydra.um.services;

import cn.com.sinux.spring.exception.BusinessException;
import cn.com.sinux.spring.exception.ServiceException;
import cn.com.sinux.spring.utils.ConvertUtils;
import cn.com.sinux.spring.utils.QueryHelper;
import cn.com.sinux.spring.utils.SpecificationHelper;
import cn.com.sinux.spring.utils.ValidatorUtils;
import com.sinosoft.hydra.um.condition.SearchBestProcessCondition;
import com.sinosoft.hydra.um.condition.SearchBestRecordCondition;
import com.sinosoft.hydra.um.constant.BaseConstant;
import com.sinosoft.hydra.um.domain.permission.*;
import com.sinosoft.hydra.um.helper.AuthContextHelper;
import com.sinosoft.hydra.um.repositories.TBestProcessDAO;
import com.sinosoft.hydra.um.repositories.TBestRecordDAO;
import com.sinosoft.hydra.um.repositories.TProcessParameterDAO;
import com.sinosoft.hydra.um.repositories.TProcessRecordDAO;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;
import java.util.*;

/**
 * Created by Administrator on 2016/8/26.
 */
@Service
public class SysBestService {

    @Autowired
    private TBestProcessDAO bestProcessDAO;
    @Autowired
    private TBestRecordDAO bestRecordDAO;
    @Autowired
    private TProcessParameterDAO processParameterDAO;
    @Autowired
    private TProcessRecordDAO processRecordDAO;
    @Autowired
    private ProcessManageService processManageService;

    /**
     * 返回单个最优流程
     *
     * @param id
     * @return
     */
    public TBestProcess findOneBestProcess(String id) {
        TBestProcess bestProcess = StringUtils.isBlank(id) ? null : bestProcessDAO.findOne(id);
        if(bestProcess != null){
            List<TBestRecord> records = bestProcess.getRecords();
            List<String> seqs = ConvertUtils.loadStringList(bestProcess.getRecordSequence(), ",");
            List<TBestRecord> sortRecords = new LinkedList<TBestRecord>();
            int i = 1;
            for(String seq : seqs){
                for(TBestRecord record : records){
                    if(seq.equals(record.getId())){
                        record.setSequenceNumber(i);
                        sortRecords.add(record);
                        i++;
                        break;
                    }
                }
            }
            bestProcess.setRecords(sortRecords);
        }
        return bestProcess;
    }

    /**
     * 查询所有最优参数
     *
     * @param id
     * @return
     */
    public List<TBestRecord> processBestRecords(String id) {
        TProcessTemplate processTemplate = processManageService.findOne(id);
        if (processTemplate == null) {
            throw new ServiceException("参数输错");
        }
        List<String> ids = QueryHelper.doQueryProperties(processTemplate.getRecords(), true, new QueryHelper.PropertyReader<TProcessRecord, String>() {

            public String read(TProcessRecord record) {
                return record.getId();
            }
        });
        return bestRecordDAO.findAll(ids);
    }

    /**
     * 批量删除最优记录
     *
     * @param ids
     * @param forceDelete
     * @return
     */
    @Transactional
    public List<TBestRecord> recordDelete(List<String> ids, boolean forceDelete) {
        if (ValidatorUtils.isArrayEmpty(ids)) {
            throw new ServiceException("参数出错");
        }
        List<TBestRecord> records = bestRecordDAO.findAll(ids);
        StringBuilder stringBuilder = new StringBuilder();
        Map<String, TBestProcess> bestProcessMap = new HashMap<String, TBestProcess>();
        for (TBestRecord record : records) {
            if (ValidatorUtils.isArrayNotEmpty(record.gettBestProcesses())) {
                List<String> pro = new ArrayList<String>();
                for (TBestProcess bestProcess : record.gettBestProcesses()) {
                    pro.add(bestProcess.getTitle());
                    bestProcessMap.put(bestProcess.getId(), bestProcess);
                }
                stringBuilder.append("最优参数").append(record.gettProcessTemplate().getProcessName()).append("隶属于流程")
                        .append(StringUtils.join(pro, ",")).append("\n");
            }
        }
        List<TBestProcess> bestProcesses = new ArrayList<TBestProcess>(bestProcessMap.values());
        if (ValidatorUtils.isArrayNotEmpty(bestProcesses)) {
            if (!forceDelete) {
                throw new BusinessException(stringBuilder.toString());
            }
            bestProcessDAO.delete(bestProcesses);
        }
        for (TBestRecord record : records) {
            processParameterDAO.delete(record.gettProcessParameters());
        }
        bestRecordDAO.delete(records);
        return records;
    }

    /**
     * 保存记录
     *
     * @return
     */
    @Transactional
    public TBestRecord saveBestRecord(TBestRecord bestRecord, BaseConstant.SaveType saveType) {
        if(BaseConstant.SaveType.SAVE_TYPE_UPDATE.equals(saveType)){
            TBestRecord db = findOneRecord(bestRecord.getId());
            if(db == null){
                throw new BusinessException("参数错误");
            }
            bestRecord.setUpdateTime(new Date());
            bestRecord.setReason(db.getReason());
            bestRecord.setType(db.getType());
            bestRecord.setCreateUser(db.getCreateUser());
            bestRecord.setOperator(db.getOperator());
            bestRecord.setOperateTime(db.getOperateTime());
            bestRecord.setCreateTime(db.getCreateTime());
            bestRecord.settProcessTemplate(db.gettProcessTemplate());
            bestRecord.settBestProcesses(db.gettBestProcesses());
            processParameterDAO.delete(db.gettProcessParameters());
        }else{
            TProcessTemplate tProcessTemplate = bestRecord.gettProcessTemplate();
            if (tProcessTemplate == null || processManageService.findOne(tProcessTemplate.getId()) == null) {
                throw new ServiceException("参数出错");
            }
            bestRecord.setCreateTime(new Date());
            bestRecord.setOperateTime(bestRecord.getCreateTime());
            bestRecord.setOperator(AuthContextHelper.getLoginUser().getUserName());
            bestRecord.setType(BaseConstant.RecordType.RECORD_TYPE_BEST.name());
            bestRecord.setCreateUser(AuthContextHelper.getLoginUser());
        }
        bestRecord.setResult(bestRecord.getReason());
        List<TProcessParameter> processParameters = bestRecord.gettProcessParameters();
        bestRecord.settProcessParameters(null);
        processRecordDAO.save(bestRecord);
        for (int j = 0; j < processParameters.size(); j++) {
            processParameters.get(j).setOrderNo(j + 1);
            processParameters.get(j).settProcessRecord(bestRecord);
        }
        processParameterDAO.save(processParameters);
        bestRecord.settProcessParameters(processParameters);
        return bestRecord;
    }


    /**
     * 查询最优流程
     *
     * @param ids
     * @return
     */
    public List<TBestProcess> deleteBestProcess(List<String> ids) {
        if (ValidatorUtils.isArrayEmpty(ids)) {
            throw new ServiceException("参数出错，请选择后再提交");
        }
        List<TBestProcess> bestProcesses = bestProcessDAO.findAll(ids);
        bestProcessDAO.delete(bestProcesses);
        return bestProcesses;
    }


    /**
     * 查询最优流程
     *
     * @param searchBestProcessCondition
     * @param pageable
     * @return
     */
    public Page<TBestProcess> findBestProcess(SearchBestProcessCondition searchBestProcessCondition, Pageable pageable) {
        return bestProcessDAO.findAll(buildSpecification(searchBestProcessCondition), pageable);
    }

    /**
     * 查询最优参数
     *
     * @param searchBestRecordCondition
     * @param pageable
     * @return
     */
    public Page<TBestRecord> findBestRecord(SearchBestRecordCondition searchBestRecordCondition, Pageable pageable) {
        return bestRecordDAO.findAll(buildRecordSpecification(searchBestRecordCondition), pageable);
    }

    /**
     * 查询最优参数
     *
     * @param id
     * @return
     */
    public TBestRecord findOneRecord(String id) {
        return StringUtils.isBlank(id) ? null : bestRecordDAO.findOne(id);
    }

    private Specification<TBestRecord> buildRecordSpecification(final SearchBestRecordCondition searchBestRecordCondition) {
        Specification<TBestRecord> specification = SpecificationHelper.buildSpecification(new SpecificationHelper.SpecificationBuilder<TBestRecord>() {

            public void fillParam(Root<TBestRecord> root, CriteriaBuilder cb, List<Predicate> list) {
                if (searchBestRecordCondition.getCreateUser() != null &&
                        StringUtils.isNotBlank(searchBestRecordCondition.getCreateUser().getUserName())) {
                    list.add(cb.like(root.get("createUser").get("userName").as(String.class), "%" + searchBestRecordCondition.getCreateUser().getUserName() + "%"));
                }
                if (StringUtils.isNotBlank(searchBestRecordCondition.getReason())) {
                    list.add(cb.like(root.get("reason").as(String.class), "%" + searchBestRecordCondition.getReason() + "%"));
                }
            }
        });
        return specification;
    }

    private Specification<TBestProcess> buildSpecification(final SearchBestProcessCondition searchBestProcessCondition) {
        Specification<TBestProcess> specification = SpecificationHelper.buildSpecification(new SpecificationHelper.SpecificationBuilder<TBestProcess>() {

            public void fillParam(Root<TBestProcess> root, CriteriaBuilder cb, List<Predicate> list) {
                if (StringUtils.isNotBlank(searchBestProcessCondition.getTitle())) {
                    list.add(cb.like(root.get("title").as(String.class), "%" + searchBestProcessCondition.getTitle() + "%"));
                }
                if (StringUtils.isNotBlank(searchBestProcessCondition.getCreator())) {
                    list.add(cb.like(root.get("creator").as(String.class), "%" + searchBestProcessCondition.getCreator() + "%"));
                }
                if (StringUtils.isNotBlank(searchBestProcessCondition.getReason())) {
                    list.add(cb.like(root.get("reason").as(String.class), "%" + searchBestProcessCondition.getReason() + "%"));
                }
            }
        });
        return specification;
    }

    /**
     * 保存最优流程
     *
     * @param bestProcess
     * @return
     */
    public TBestProcess saveBestProcess(TBestProcess bestProcess, BaseConstant.SaveType saveType) {
        if(BaseConstant.SaveType.SAVE_TYPE_UPDATE.equals(saveType)){
            TBestProcess db = bestProcessDAO.findOne(bestProcess.getId());
            if(db == null){
                throw new BusinessException("参数错误");
            }
        }
        List<TBestRecord> records = bestProcess.getRecords();
        if (ValidatorUtils.isArrayEmpty(records)) {
            throw new BusinessException("没有保存详细的流程，保存失败");
        }
        bestProcess.setCreator(AuthContextHelper.getLoginUser().getUserName());
        bestProcess.setCreateTime(new Date());
        List<String> recordSequence = new LinkedList<String>();
        for (TBestRecord record : records) {
            recordSequence.add(record.getId());
        }
        bestProcess.setRecordSequence(StringUtils.join(recordSequence, ","));
        bestProcessDAO.save(bestProcess);
        return bestProcess;
    }
}
